Merge past #1939.
authorJeffrey Yasskin <jyasskin@gmail.com>
Tue, 1 Sep 2015 03:56:35 +0000 (20:56 -0700)
committerJeffrey Yasskin <jyasskin@gmail.com>
Tue, 1 Sep 2015 03:56:35 +0000 (20:56 -0700)
1  2 
src/cargo/core/resolver/mod.rs

index 6dd3f06715df1c61d707093f00779b61268839dc,702248260301e90e110071b5cc3b928be9fe4455..87894d90d2f8254c5caa78abf15916fa5d0284bd
@@@ -236,177 -289,80 +235,167 @@@ fn activate(cx: &mut Context
      }
      trace!("activating {}", parent.package_id());
  
 -    let deps = try!(cx.build_deps(registry, parent, method));
 +    let deps = try!(cx.build_deps(registry, &parent, method));
  
-     // Extracting the platform request.
-     let platform = match *method {
-         Method::Required { target_platform, .. } => target_platform,
-         Method::Everything => None,
-     };
 -    activate_deps(cx, registry, parent, deps.iter(), 0, &mut |mut cx, registry| {
 -        cx.visited.remove(id);
 -        finished(cx, registry)
 -    })
 +    Ok(Some(DepsFrame{
 +        parent: parent,
 +        remaining_siblings: RcVecIter::new(deps),
-         platform: platform.map(|s| s.to_string()),
 +        id: id,
 +    }))
  }
  
 -/// Activates the dependencies for a package, one by one in turn.
 -///
 -/// This function will attempt to activate all possible candidates for each
 -/// dependency of the package specified by `parent`. The `deps` iterator
 -/// provided is an iterator over all dependencies where each element yielded
 -/// informs us what the candidates are for the dependency in question.
 +#[derive(Clone)]
 +struct RcVecIter<Elem> {
 +    vec: Rc<Vec<Elem>>,
 +    next_index: usize,
 +}
 +
 +impl<Elem> RcVecIter<Elem> {
 +    fn new(vec: Vec<Elem>) -> RcVecIter<Elem> {
 +        RcVecIter {
 +            vec: Rc::new(vec),
 +            next_index: 0
 +        }
 +    }
 +    fn next(&mut self) -> Option<(usize, &Elem)> {
 +        match self.vec.get(self.next_index) {
 +            None => None,
 +            Some(val) => {
 +                let index = self.next_index;
 +                self.next_index += 1;
 +                Some((index, val))
 +            }
 +        }
 +    }
 +}
 +
 +#[derive(Clone)]
 +struct DepsFrame {
 +    parent: Rc<Summary>,
 +    remaining_siblings: RcVecIter<DepInfo>,
-     platform: Option<String>,
 +    id: PackageId,
 +}
 +type RemainingDeps = Vec<DepsFrame>;
 +
 +struct BacktrackFrame {
 +    context_backup: Context,
 +    deps_backup: RemainingDeps,
 +    remaining_candidates: RcVecIter<Rc<Summary>>,
 +    // For building an activation error:
 +    parent: Rc<Summary>,
 +    cur: usize,
 +    dep: Rc<Dependency>,
 +    prev_active: Vec<Rc<Summary>>,
 +    all_candidates: Vec<Rc<Summary>>,
 +}
 +
 +/// Recursively activates the dependencies for `top`, in depth-first order,
 +/// backtracking across possible candidates for each dependency as necessary.
  ///
  /// If all dependencies can be activated and resolved to a version in the
 -/// dependency graph the `finished` callback is invoked with the current state
 -/// of the world.
 -fn activate_deps<'a>(cx: Box<Context>,
 -                     registry: &mut Registry,
 -                     parent: &Summary,
 -                     mut deps: slice::Iter<'a, DepInfo>,
 -                     cur: usize,
 -                     finished: &mut FnMut(Box<Context>, &mut Registry) -> ResolveResult)
 -                     -> ResolveResult {
 -    let &(dep, ref candidates, ref features) = match deps.next() {
 -        Some(info) => info,
 -        None => return finished(cx, registry),
 -    };
 +/// dependency graph, cx.resolve is returned.
 +fn activate_deps_loop(mut cx: Context,
 +                      registry: &mut Registry,
 +                      top: Rc<Summary>,
 +                      top_method: &Method) -> CargoResult<Resolve> {
 +    let mut backtrack_stack: Vec<BacktrackFrame> = Vec::new();
 +    let mut remaining_deps: RemainingDeps = Vec::new();
 +    remaining_deps.extend(
 +        try!(activate(&mut cx, registry, top, &top_method)));
 +    loop {
 +        // Retrieves the next dependency to try, from `remaining_deps`.
-         let (parent, platform, cur, dep, candidates, features) =
++        let (parent, cur, dep, candidates, features) =
 +            match remaining_deps.pop() {
 +                None => break,
 +                Some(mut deps_frame) => {
 +                    let info =
 +                        match deps_frame.remaining_siblings.next() {
 +                            Some((cur, &(ref dep, ref candidates, ref features))) =>
-                                 (deps_frame.parent.clone(), deps_frame.platform.clone(),
-                                  cur, dep.clone(),
++                                (deps_frame.parent.clone(), cur, dep.clone(),
 +                                 candidates.clone(), features.clone()),
 +                            None => {
 +                                cx.visited.remove(&deps_frame.id);
 +                                continue;
 +                            }
 +                        };
 +                    remaining_deps.push(deps_frame);
 +                    info
 +                }
 +            };
  
 -    let method = Method::Required {
 -        dev_deps: false,
 -        features: features,
 -        uses_default_features: dep.uses_default_features(),
 -    };
 +        let method = Method::Required {
 +            dev_deps: false,
 +            features: &features,
 +            uses_default_features: dep.uses_default_features(),
-             target_platform: platform.as_ref().map(|p| p as &str),
 +        };
  
 -    let prev_active = cx.prev_active(dep);
 -    trace!("{}[{}]>{} {} candidates", parent.name(), cur, dep.name(),
 -           candidates.len());
 -    trace!("{}[{}]>{} {} prev activations", parent.name(), cur,
 -           dep.name(), prev_active.len());
 -
 -    // Filter the set of candidates based on the previously activated
 -    // versions for this dependency. We can actually use a version if it
 -    // precisely matches an activated version or if it is otherwise
 -    // incompatible with all other activated versions. Note that we define
 -    // "compatible" here in terms of the semver sense where if the left-most
 -    // nonzero digit is the same they're considered compatible.
 -    let my_candidates = candidates.iter().filter(|&b| {
 -        prev_active.iter().any(|a| a == b) ||
 -            prev_active.iter().all(|a| {
 -                !compatible(a.version(), b.version())
 -            })
 -    });
 +        let prev_active: Vec<Rc<Summary>> = cx.prev_active(&dep).to_vec();
 +        trace!("{}[{}]>{} {} candidates", parent.name(), cur, dep.name(),
 +               candidates.len());
 +        trace!("{}[{}]>{} {} prev activations", parent.name(), cur,
 +               dep.name(), prev_active.len());
 +
 +        // Filter the set of candidates based on the previously activated
 +        // versions for this dependency. We can actually use a version if it
 +        // precisely matches an activated version or if it is otherwise
 +        // incompatible with all other activated versions. Note that we define
 +        // "compatible" here in terms of the semver sense where if the left-most
 +        // nonzero digit is the same they're considered compatible.
 +        let my_candidates: Vec<Rc<Summary>> = candidates.iter().filter(|&b| {
 +            prev_active.iter().any(|a| a == b) ||
 +                prev_active.iter().all(|a| {
 +                    !compatible(a.version(), b.version())
 +                })
 +        }).cloned().collect();
 +
 +        // Alright, for each candidate that's gotten this far, it meets the
 +        // following requirements:
 +        //
 +        // 1. The version matches the dependency requirement listed for this
 +        //    package
 +        // 2. There are no activated versions for this package which are
 +        //    semver-compatible, or there's an activated version which is
 +        //    precisely equal to `candidate`.
 +        //
 +        // This means that we're going to attempt to activate each candidate in
 +        // turn. We could possibly fail to activate each candidate, so we try
 +        // each one in turn.
 +        let mut remaining_candidates = RcVecIter::new(my_candidates);
 +        let maybe_candidate =
 +            remaining_candidates.next().map(|(_, candidate)| candidate.clone());
 +        let candidate: Rc<Summary> = match maybe_candidate {
 +            Some(candidate) => {
 +                // We have a candidate. Add an entry to the `backtrack_stack` so
 +                // we can try the next one if this one fails.
 +                backtrack_stack.push(BacktrackFrame {
 +                    context_backup: cx.clone(),
 +                    deps_backup: remaining_deps.clone(),
 +                    remaining_candidates: remaining_candidates,
 +                    parent: parent.clone(),
 +                    cur: cur,
 +                    dep: dep.clone(),
 +                    prev_active: prev_active,
 +                    all_candidates: candidates,
 +                });
 +                candidate
 +            }
 +            None => {
 +                // This dependency has no valid candidate. Backtrack until we
 +                // find a dependency that does have a candidate to try, and try
 +                // to activate that one.  This resets the `remaining_deps` to
 +                // their state at the found level of the `backtrack_stack`.
 +                trace!("{}[{}]>{} -- None", parent.name(), cur, dep.name());
 +                let last_err = activation_error(&cx, registry, None, &parent, &dep,
 +                                                &prev_active, &candidates);
 +                try!(find_candidate(&mut backtrack_stack, &mut cx, &mut remaining_deps,
 +                                    registry, last_err))
 +            }
 +        };
  
 -    // Alright, for each candidate that's gotten this far, it meets the
 -    // following requirements:
 -    //
 -    // 1. The version matches the dependency requirement listed for this
 -    //    package
 -    // 2. There are no activated versions for this package which are
 -    //    semver-compatible, or there's an activated version which is
 -    //    precisely equal to `candidate`.
 -    //
 -    // This means that we're going to attempt to activate each candidate in
 -    // turn. We could possibly fail to activate each candidate, so we try
 -    // each one in turn.
 -    let mut last_err = None;
 -    for candidate in my_candidates {
          trace!("{}[{}]>{} trying {}", parent.name(), cur, dep.name(),
                 candidate.version());
 -        let mut my_cx = cx.clone();
 -        my_cx.resolve.graph.link(parent.package_id().clone(),
 -                                 candidate.package_id().clone());
 +        cx.resolve.graph.link(parent.package_id().clone(),
 +                              candidate.package_id().clone());
  
          // If we hit an intransitive dependency then clear out the visitation
          // list as we can't induce a cycle through transitive dependencies.